package triFileSystem;

import transaction.Transaction;
import triStorage.*;
import utils.*;

public class EndRPageArray implements IReader {

	PageDir inode;
	int endPageId;
	int endPos;
	TriMMPFile mmpfile;
	
	int pos;
	int pageId;
	int idx;
	
	public EndRPageArray(PageDir inode, long offset, TriMMPFile mmpfile) {
		this.inode = inode;
		endPageId = (int)(offset / mmpfile.PAGE_SIZE);
		endPos = (int) (offset % mmpfile.PAGE_SIZE);
		this.mmpfile = mmpfile;
		
		idx = 0;
		pageId = inode.getIthPageId(idx);
		pos = Constants.INT_SIZE;
	}	
	
	@Override
	public void seek(long readPos) {
		pageId = (int)((readPos - 1) / mmpfile.PAGE_SIZE);
		pos = (int)((readPos - 1) % mmpfile.PAGE_SIZE) + 1;
		
		for (idx = 0; ; ++idx) {
			int temp = inode.getIthPageId(idx);
			if (temp < 0 || temp == pageId)
				break;
		}
	}
	
	@Override
	public Integer readInt() {
		if (isLast())
			return null;
		
		int value;
		int length = mmpfile.readInt(pageId, 0);

		if (pos + Constants.INT_SIZE > length) {
			if (!moveNextPage())
				return null;
		}
		
		value = mmpfile.readInt(pageId, pos);
		pos += Constants.INT_SIZE;
		return value;
	}
	
	@Override
	public Long readLong() {
		if (isLast())
			return null;
		
		long value;
		int length = mmpfile.readInt(pageId, 0);

		if (pos + Constants.LONG_SIZE > length) {
			if (!moveNextPage())
				return null;
			//++idx;
			
		}
		
		value = mmpfile.readLong(pageId, pos);
		pos += Constants.LONG_SIZE;
		return value;
	}

	@Override
	public String readString() {
		Integer strLen = readInt();
		if (strLen == null || strLen < 0)
			return null;
		else if (strLen == 0)
			return "";
		
		byte[] bytes = new byte[strLen];
		int length;
			//start position
		for (int i = 0, count; i < strLen; ) {
			length = mmpfile.readInt(pageId, 0);
			if (length - pos <= strLen - i)
				count = length - pos;
			else
				count = strLen - i;
			mmpfile.readBytes(pageId, pos, bytes, i, count);
			i += count;
			pos += count;
			if (i < strLen) {
				if (!moveNextPage())
					return null;
			}
		}
			
		return Converter.Bytes2String(bytes, 0);
	}

	@Override
	public void skipString() {
		Integer strLen = readInt();
		if (strLen == null || strLen <= 0)
			return;
		
		//start position
		int length;
		for (int i = 0, count; i < strLen; ) {
			length = mmpfile.readInt(pageId, 0);
			if (length - pos <= strLen - i)
				count = length - pos;
			else
				count = strLen - i;
			i += count;
			pos += count;
			if (i < strLen) {
				if (!moveNextPage())
					return;
			}
		}
		
	}
	
	@Override
	public long getReadPos() {
		return pageId * mmpfile.PAGE_SIZE + pos;
	}


	private boolean isLast() {
		if (pageId == endPageId && pos >= endPos)
			return true;
		return false;
	}
	
	private boolean moveNextPage() {
		if (isLast())
			return false;
		++idx;
		pageId = inode.getIthPageId(idx);
		pos = Constants.INT_SIZE;
		return true;
	}

	@Override
	//doesn't support
	public IWriter toWriter(Transaction tx) {
		return null;
	}

	@Override
	public void dispose() {
	}


	
}
